//
// Created by sherlock on 2021/2/28.
//

#include "TcpServer.h"
#include "TcpSocket.h"

class TcpServerPrivateData
{
public:
    uv_loop_t *loop;
    uv_tcp_t *server;
    std::string ip;
    unsigned int port;
    unsigned int maxConnection;
    std::string lastErrorMessage;

    TcpServer::OnNewConnect onNewConnect;
    void *userData;
};

TcpServer::TcpServer()
{
    data = std::unique_ptr<TcpServerPrivateData>(new TcpServerPrivateData());
}

TcpServer::TcpServer(uv_loop_t *loop)
{
    data = std::unique_ptr<TcpServerPrivateData>(new TcpServerPrivateData());
    data->loop = loop;
    initializeData();
}

TcpServer::~TcpServer()
{

}

void TcpServer::initializeData()
{
    data->maxConnection = 128;
    data->server = static_cast<uv_tcp_t *>(malloc(sizeof(uv_tcp_t)));
}

void TcpServer::setMaxConnect(unsigned int max)
{
    data->maxConnection = max;
}

bool TcpServer::listen(TcpServer::HostAddress hostAddress, unsigned int port)
{
    data->port = port;

    uv_tcp_init(data->loop, data->server);//初始化tcp server对象
    struct sockaddr_in addr;
    uv_ip4_addr("0.0.0.0", port, &addr);//将ip和port数据填充到sockaddr_in结构体中
    uv_tcp_bind(data->server, (const struct sockaddr *) &addr, 0);//bind

    data->server->data = (void *) this;
    int res = uv_listen((uv_stream_t *) data->server, data->maxConnection, TcpServer::newConnectionCB);//listen
    if (res)
    {
        data->lastErrorMessage = getErrorMessage(res);
        return false;
    }
    return true;
}

std::string TcpServer::getLastErrorMessage() const
{
    return data->lastErrorMessage;
}

std::string TcpServer::getErrorMessage(int errorCode)
{
    const char *errName = uv_strerror(errorCode);
    return std::string(errName);
}

void TcpServer::newConnectionCB(uv_stream_t *server, int status)
{
    auto *thisPoint = (TcpServer *) server->data;

    if (status < 0)
    {
        thisPoint->data->lastErrorMessage = getErrorMessage(status);
        return;
    }

    auto *client = (uv_tcp_t *) malloc(sizeof(uv_tcp_t));//为tcp client申请资源

    uv_tcp_init(thisPoint->data->loop, client);//初始化tcp client句柄
    client->data = server->data;

    //判断accept是否成功
    if (uv_accept(server, (uv_stream_t *) client) == 0)
    {
        //从传入的stream中读取数据，read_cb会被多次调用，直到数据读完，或者主动调用uv_read_stop方法停止
        TcpSocket *pSocket = new TcpSocket(client);
        thisPoint->newConnect(pSocket);
        if (thisPoint->data->onNewConnect)
        {
            thisPoint->data->onNewConnect(pSocket, thisPoint->data->userData);
        }
    }
    else
    {
        uv_close((uv_handle_t *) client, nullptr);
    }
}

void TcpServer::newConnect(TcpSocket *tcpSocket)
{

}

void TcpServer::setNewConnectCB(TcpServer::OnNewConnect onNewConnect, void *userData)
{
    data->onNewConnect = onNewConnect;
    data->userData = userData;
}



